home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1995 October
/
EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso
/
Aminet
/
comm
/
tcp
/
ftpd2.lha
/
ftpd2
/
ftpserv.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-05-02
|
25KB
|
979 lines
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <error.h>
#include <stat.h>
#include <dos.h>
#include <sys/ioctl.h>
#include <sys/dir.h>
#include <lineread.h>
#include <sys/socket.h>
#include <exec/memory.h>
#include <dos/dostags.h>
#include <libraries/multiuser.h>
#include <proto/exec.h>
#include <proto/socket.h>
#include <proto/multiuser.h>
#include <proto/dos.h>
#include "ftp.h"
struct muBase *muBase;
extern LONG server_socket;
char VersionTag[]="\0$VER: JoranFtpd 2.0 (14.12.93)";
char Hostname[40]="unknown";
char Version[]="Joran 2.0";
char buf2[512];
int tt1, tt2, tnw;
int pdata=-1; // For passive mode
struct FileInfoBlock *PermChkFib;
struct muUserInfo *UserInfo;
long gethostname(char *,long len);
struct LineRead *LineRead;
/* Command table */
static char *commands[] = {
"user",
"acct",
"pass",
"type",
"list",
"cwd",
"dele",
"name",
"quit",
"retr",
"stor",
"port",
"nlst",
"pwd",
"xpwd", /* For compatibility with 4.2BSD */
"mkd ",
"xmkd", /* For compatibility with 4.2BSD */
"xrmd", /* For compatibility with 4.2BSD */
"rmd ",
"stru",
"mode",
"pasv", /* Pasive mode */
NULL
};
/* Response messages */
static char binwarn[] = "100 Warning: File %s appears to be BINARY\n";
static char sending[] = "150 Open %s for %s %s (%ld Bytes)\n";
static char recving[] = "150 Open %s for %s %s\n";
static char typeok[] = "200 Type %s OK\n";
static char mkdok[] = "200 MKD ok\n";
static char portok[] = "200 Port command okay\n";
static char okay[] = "200 Ok\n";
static char banner[] = "220 %s FTP Ready - v%s\n";
static char bye[] = "221 Goodbye!\n";
static char rxok[] = "226 File received OK\n";
static char txok[] = "226 File sent OK\n";
static char logged[] = "230 %s Logged in, %s\n";
static char loggeda[] = "230 %s Logged in as anonymous, %s\n";
static char deleok[] = "250 File deleted\n";
static char pwdmsg[] = "257 \"%s\" is current directory\n";
static char givepass[] = "331 Enter Password\n";
static char givepasa[] = "331 Please enter your email address '<user-id>@<host-name>'\n";
static char lowmem[] = "421 System overloaded, try again later\n";
static char noconn[] = "425 Data connection reset\n";
static char unsupp[] = "500 Unsupported command or option\n";
static char badcmd[] = "500 Unknown command\n";
static char only8[] = "501 Only logical bytesize 8 supported\n";
static char badtype[] = "501 Unknown type \"%s\"\n";
static char badport[] = "501 Bad port syntax\n";
static char unimp[] = "502 Command not yet implemented\n";
static char userfirst[] = "503 Login with USER first.\n";
static char notlog[] = "530 Please log in with USER and PASS\n";
static char noperm[] = "550 Permission denied\n";
static char cantopen[] = "550 Can't read file \"%s\": %s\n";
static char delefail[] = "550 Delete failed: %s\n";
static char writerr[] = "552 Write error: %s\n";
static char nodir[] = "553 Can't read directory \"%s\": %s\n";
static char cantmake[] = "553 Can't create \"%s\": %s\n";
static char notyet[] = "555 Try Later : Access '%2d:00-%2d:59 %s' only\n";
static char nopasv[] = "425 Can't open passive connection\n";
static char pasvcon[] = "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\n";
void CloseAll(void)
{
if(UserInfo) muFreeUserInfo(UserInfo);
if(PermChkFib) FreeDosObject(DOS_FIB,PermChkFib);
if(LineRead) FreeMem(LineRead,sizeof(struct LineRead));
if(muBase) CloseLibrary((struct Library *)muBase);
if(LogLevel>=20) AddLog("FTPDeamon Stopped",FindTask(NULL));
}
void InitAll(void)
{
atexit(CloseAll);
SetProgramName("JoranFtpd");
muBase=(struct muBase *)OpenLibrary(MULTIUSERNAME,MULTIUSERVERSION);
if(muBase && !(UserInfo=muAllocUserInfo())) exit(20);
gethostname(Hostname,sizeof(Hostname));
if(!(LineRead=AllocMem(sizeof(struct LineRead),MEMF_ANY))) exit(20);
initLineRead(LineRead,server_socket,RL_LFREQLF,RL_BUFSIZE);
if(!(PermChkFib=AllocDosObject(DOS_FIB,NULL))) exit(20);
}
/* replace terminating end of line marker(s) with null */
void rip(char *s)
{
char *cp;
if((cp = strchr(s,'\n')) != NULL) *cp = '\0';
if((cp = strchr(s,'\r')) != NULL) *cp = '\0';
}
/* This checks the current time is in a preset Time-Window before
allowing a user to login */
int timewind(int argc,char *argv[],void *p)
{
char *now;
long t;
char *t1, *t2;
t1 = strdup(curftwin);
*(t1 + 2) = '\0';
tt1 = atoi(t1);
t2 = strdup(curftwin+2);
*(t2 + 2) = '\0';
tt2 = atoi(t2);
time(&t);
now = ctime(&t) + 11;
*(now + 2) = '\0';
tnw = atoi(now);
if(tt1 > tt2) {
if(((tnw >= tt1) && (tnw <= 23)) ||
((tnw <= tt2) && (tnw >= 0)))
return 0; /* right in time */
} else {
if((tnw >= tt1) && (tnw <= tt2))
return 0; /* right in time */
}
return 1;
}
/* Return 1 if the file operation is allowed, 0 otherwise */
int permcheck(char *path,int perms,int op,char *file)
{
BPTR l;
BYTE prot;
if(file == NULL || path == NULL)
return 0; /* Probably hasn't logged in yet */
/* The target file must be under the user's allowed search path */
if(strncmp(file,path,strlen(path)) != 0)
return 0;
prot=-1;
// if(muBase & perms&FTP_MULTIUSER)
// {
// Check default protection
// if(l=Lock(file,ACCESS_READ))
// {
// if(Examine(l,PermChkFib))
// {
// if(UserInfo->uid==muNOBODYUID)
// {
//
// }
// if(UserInfo->uid==PermChkFib->fib_OwnerUID)
// {
// }
// if(UserInfo->gid==PermChkFib->fib_GroupUID)
// {
// }
//
// }
// UnLock(l);
// }
// }
if(l=Lock(file,ACCESS_READ)) UnLock(l);
switch(op){
case RETR_CMD:
/* User must have permission to read files */
if(perms&FTP_READ && prot&FIBF_READ)
return 1;
return 0;
case DELE_CMD:
case RMD_CMD:
/* User must have permission to (over)write files */
if(perms&FTP_WRITE && prot&FIBF_DELETE)
return 1;
return 0;
case STOR_CMD:
case MKD_CMD:
/* User must have permission to (over)write files, or permission
* to create them if the file doesn't already exist
*/
if(!l && perms&FTP_CREATE) return 1;
if(l && perms&FTP_WRITE && prot&FIBF_DELETE)
return 1;
return 0;
}
return 0; /* "can't happen" -- keep lint happy */
}
/* Subroutine for logging in the user whose name is name and
password is pass. The buffer path should be long enough to
keep a line from the userfile. If pwdignore is true, the
password check will be overridden. The return value is the
permissions field or -1 if the login failed. Path is set to
point at the path field, and pwdignore will be true if no
particular password was needed for this user.
*/
int userlogin(char *name,char *pass,char **path,int len,int *pwdignore)
{
char *cp,*cp1;
FILE *fp;
char *rest = NULL;
int anony, perm;
int unknown=FALSE;
*pwdignore=!strcmp("ftp",name);
anony = *pwdignore;
if((fp = fopen(Userfile,"r")) == NULL) return -1; /* Userfile doesn't exist */
while(fgets(*path,len,fp),!feof(fp))
{
if(*path[0] == '#') continue; /* Comment */
if((cp=strchr(*path,' '))==NULL) continue; /* Bogus entry */
*cp++ = '\0'; /* Now points to password */
if(stricmp(name,*path)==0) break; /* Found user name */
if(stricmp("rest",*path)==0) rest=strdup(cp); /* remember default entry */
}
unknown=feof(fp);
if((rest==NULL) && unknown)
{
/* User not in file, nor was anonymous */
fclose(fp);
return -1;
}
if(unknown)
{
/* restore default entry */
strcpy(cp = *path, rest);
}
fclose(fp);
/* Look for space after password field in file */
if((cp1 = strchr(cp,' ')) == NULL) return -1; /* Invalid file entry */
*cp1++ = '\0'; /* Now points to path field */
if(strcmp(cp,"*")!=0)
{
if(strcmp(cp,pass)!=0) return -1; /* Password required, but wrong one given */
}
if((cp = strchr(cp1,' ')) == NULL) return -1; /* Permission field missing */
*cp++ = '\0'; /* now points to permission field */
perm = atoi(cp);
if(unknown && (!muBase || !perm&FTP_MULTIUSER)) return -1;
if(muBase && perm&FTP_MULTIUSER)
{
strncpy(UserInfo->UserID,name,muUSERIDSIZE);
if(!muGetUserInfo(UserInfo,muKeyType_UserID))
{
if(LogLevel>=10) AddLog("Unknown User \"%s\"",name);
return -1;
}
if(!muLogin(
muT_UserID,UserInfo->UserID,
muT_Password,anony?"":pass,
TAG_DONE
))
{
if(LogLevel>=10) AddLog("Wrong password for \"%s\"",UserInfo->UserID);
return -1;
}
}
/*
* Well, on the Amiga, a file can be referenced by many names:
* device names (DF0:) or volume names (My_Disk:). This hunk of code
* passed the pathname specified in the ftpusers file, and gets the
* absolute path copied into the user's buffer. We really should just
* allocate the buffer and return a pointer to it, since the caller
* really doesn't have a good idea how long the path string is..
*/
if(cp1[0]=='*') cp1=strdup("");
else cp1=pathname("",cp1);
if (cp1) strcpy(*path, cp1);
else **path = '\0';
free(cp1);
/* Finally return the permission bits */
return perm;
}
/* Attempt to log in the user whose name is in ftp->username and password
* in pass
*/
static void ftplogin(struct ftpserv *ftp,char *pass)
{
long t;
char *path,buf2[77],*cp,*cp1;
int anony = 0;
FILE *fp;
path = malloc(200);
if((ftp->perms=userlogin(ftp->username,pass,&path,200,&anony)) == -1)
{
usprintf(ftp->control,noperm);
free(path);
return;
}
/* Set up current directory and path prefix */
if(*path) ftp->cd=strdup(path);
else
{
if(muBase) ftp->cd=pathname(UserInfo->HomeDir,"");
else ftp->cd=pathname(":","");
}
ftp->path = strdup(path);
free(path);
sprintf(buf2,"%sFTP.After",SignOn);
if((fp = fopen(buf2,"r")) != NULL)
{
sendfile(fp,ftp->control,ASCII_TYPE,0);
fclose(fp);
}
time(&t);
cp = ctime(&t);
if((cp1 = strchr(cp,'\n')) != NULL) *cp1 = '\0';
if(!anony)
{
usprintf(ftp->control,logged,ftp->username,cp);
if(LogLevel>=15) AddLog("%s logged in",ftp->username);
}
else
{
usprintf(ftp->control,loggeda,
strcmp(ftp->username,"ftp") ?
ftp->username : "",cp);
if(LogLevel>=15) AddLog("%s logged in, ID %s",ftp->username,pass);
}
}
static int sendit(struct ftpserv *ftp,char *command,char *file)
{
long total;
struct sockaddr_in dport;
struct stat stb;
ftp->data = socket(AF_INET,SOCK_STREAM,0);
dport.sin_family=AF_INET;
dport.sin_addr.s_addr=INADDR_ANY;
dport.sin_port=IPPORT_FTPD;
bind(ftp->data,(struct sockaddr *)&dport,sizeof(struct sockaddr_in));
stat(file,&stb);
usprintf(ftp->control,sending,file,ftp->type ? "BINARY" : "ASCII",command,stb.st_size);
if(connect(ftp->data,(struct sockaddr *)&ftp->port,sizeof(struct sockaddr_in)) == -1){
fclose(ftp->fp);
ftp->fp = NULL;
CloseSocket(ftp->data);
ftp->data = -1;
ftp->pdata = -1;
usprintf(ftp->control,noconn);
return -1;
}
//#ifdef FTPTDISC
/* Turn of the timeout timer here, some ftp's could
* take a long time with sloooow packet channels - WG7J
*/
// stop_timer(&ftp->tdisc);
//#endif
/* Do the actual transfer */
total = sendfile(ftp->fp,ftp->data,ftp->type,0);
//#ifdef FTPTDISC
/* And turn it back on now */
// start_timer(&ftp->tdisc);
//#endif
if(total == -1)
{
/* An error occurred on the data connection */
usprintf(ftp->control,noconn);
shutdown(ftp->data,2); /* Blow away data connection */
} else usprintf(ftp->control,txok);
fclose(ftp->fp);
ftp->fp = NULL;
CloseSocket(ftp->data);
ftp->data = -1;
ftp->pdata = -1;
if(total == -1) return -1;
else return 0;
}
int recvit(struct ftpserv *ftp,char *command,char *file)
{
struct sockaddr_in dport;
long total;
ftp->data=socket(AF_INET,SOCK_STREAM,0);
dport.sin_family=AF_INET;
dport.sin_addr.s_addr=INADDR_ANY;
dport.sin_port = IPPORT_FTPD;
bind(ftp->data,(struct sockaddr *)&dport,sizeof(struct sockaddr_in));
usprintf(ftp->control,recving,file,ftp->type?"BINARY":"ASCII",command);
if(connect(ftp->data,(struct sockaddr *)&ftp->port,sizeof(struct sockaddr_in)) == -1)
{
fclose(ftp->fp);
ftp->fp = NULL;
CloseSocket(ftp->data);
ftp->data = -1;
ftp->pdata = -1;
usprintf(ftp->control,noconn);
return -1;
}
//#ifdef FTPTDISC
/* Turn of the timeout timer here; some ftp's could
* take a long time with sloooow packet channels - WG7J
*/
// stop_timer(&ftp->tdisc);
//#endif
/* Do the actual transfer */
total = recvfile(ftp->fp,ftp->data,ftp->type,0);
//#ifdef FTPTDISC
/* And turn it back on now */
// start_timer(&ftp->tdisc);
//#endif
if(total == -1)
{
/* An error occurred while writing the file */
usprintf(ftp->control,writerr,sys_errlist[errno]);
shutdown(ftp->data,2); /* Blow it away */
}
else
{
usprintf(ftp->control,rxok);
CloseSocket(ftp->data);
}
ftp->data = -1;
ftp->pdata = -1;
fclose(ftp->fp);
ftp->fp = NULL;
if(total == -1) return -1;
else return 0;
}
static int pport(struct sockaddr_in *sock,char *arg)
{
int n;
int i;
n = 0;
for(i=0;i<4;i++)
{
n = atoi(arg) + (n << 8);
if((arg = strchr(arg,',')) == NULL) return -1;
arg++;
}
sock->sin_addr.s_addr = n;
n = atoi(arg);
if((arg = strchr(arg,',')) == NULL) return -1;
arg++;
n = atoi(arg) + (n << 8);
sock->sin_port = n;
return 0;
}
FILE *dir(char *path,int full)
{
int ftotal=0, fnumbr=0;
BPTR FrameLock_p;
struct FileInfoBlock *fib_p;
FILE *f;
char wildcard[40],*p=NULL;
char parsecard[82];
if(strchr(path,'*') || strchr(path,'?')) p=FilePart(path);
if(p)
{
strncpy(wildcard,p,sizeof(wildcard));
wildcard[sizeof(wildcard)-1]='\0';
p=PathPart(path);
if(p) *p='\0';
} else strcpy(wildcard,"*");
if(ParsePatternNoCase(wildcard,parsecard,sizeof(parsecard))<=0) return NULL;
if((f=tmpfile())==NULL) return NULL;
if(FrameLock_p=Lock(path,ACCESS_READ))
{
if (fib_p=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC))
{
if(Examine(FrameLock_p,fib_p))
{
if(fib_p->fib_DirEntryType<0)
fprintf(f,"You can only use this command with a Directory Name\n");
else
{
if(full) fprintf(f," Size File/Dir Name Comment\n");
while(ExNext(FrameLock_p,fib_p))
{
if(MatchPatternNoCase(parsecard,fib_p->fib_FileName))
{
if(full)
{
if(fib_p->fib_DirEntryType>0)
{
fprintf(f," (Dir) ");
}
else if(fib_p->fib_Size == 0)
{
fprintf(f," (empty) ");
}
else
{
ftotal=ftotal+fib_p->fib_Size;
fnumbr++;
fprintf(f,"%8d ",fib_p->fib_Size);
}
fprintf(f,"%-16s", fib_p->fib_FileName);
fprintf(f,strlen(fib_p->fib_Comment) ? " : %-30s\n" : "\n",
fib_p->fib_Comment);
}
else if(fib_p->fib_DirEntryType<0) fprintf(f,"%s\n", fib_p->fib_FileName);
}
}
if(full)
fprintf(f, "Directory %s : %d Bytes : %d Files\n", path, ftotal, fnumbr);
}
}
FreeMem(fib_p,sizeof(struct FileInfoBlock));
}
UnLock(FrameLock_p);
}
rewind(f);
return f;
}
FILE *extdir(char *arg)
{
BPTR f;
FILE *fp;
char fn[30];
sprintf(fn,"T:JoranFtpd%08X",FindTask(NULL));
if(*arg) sprintf(buf2,ArgDirCommand,arg);
else sprintf(buf2,DefDirCommand,arg);
if(LogLevel>=30) AddLog("%s",buf2);
if(f=Open(fn,MODE_NEWFILE))
{
SystemTags(buf2,
SYS_Output,f,
TAG_DONE
);
Close(f);
if(fp=fopen(fn,"r")) return fp;
}
return NULL;
}
/* Note: a response of 425 is not mentioned as a possible response to the
* PASV command in RFC959. However, it has been blessed as a legitimate
* response by Jon Postel in a telephone conversation with Rick Adams on 25
* Jan 89. */
void passive(struct ftpserv *ftp)
{
LONG len;
register char *p,*a;
ftp->pdata = socket(AF_INET, SOCK_STREAM, 0);
if (ftp->pdata < 0) {
usprintf(ftp->control,nopasv);
return;
}
ftp->pasv = ftp->port;
ftp->pasv.sin_port = 0;
// (void) seteuid((uid_t) 0);
if (bind(ftp->pdata, (struct sockaddr *) &ftp->pasv, sizeof(ftp->pasv)) < 0) {
// (void) seteuid((uid_t) pw->pw_uid);
goto pasv_error;
}
//(void) seteuid((uid_t) pw->pw_uid);
len = sizeof(ftp->pasv);
if (getsockname(ftp->pdata, (struct sockaddr *) &ftp->pasv, &len) < 0)
goto pasv_error;
if (listen(ftp->pdata, 1) < 0)
goto pasv_error;
a = (char *) &ftp->pasv.sin_addr;
p = (char *) &ftp->pasv.sin_port;
#define UC(b) (((int) b) & 0xff)
usprintf(ftp->control,pasvcon,
UC(a[0]),UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
return;
pasv_error:
CloseSocket(ftp->pdata);
ftp->pdata = -1;
usprintf(ftp->control,nopasv);
return;
}
main()
{
struct ftpserv ftp;
FILE *fp;
long l,cnt;
char *buf,*arg;
char **cmdp,*p;
char *file,*mode;
fd_set readfds;
AddLog("FTPDeamon Initialising");
if(server_socket==-1) exit(20);
InitAll();
ReadConfig();
memset((char *)&ftp,0,sizeof(ftp)); /* Start with clear slate */
ftp.data=-1;
ftp.pdata=-1;
ftp.control=server_socket;
l=sizeof(struct sockaddr_in);
getpeername(server_socket,(struct sockaddr *)&ftp.port,&l);
ftp.port.sin_port=IPPORT_FTPD;
if(LogLevel>=20) AddLog("FTPDeamon started",FindTask(NULL));
sprintf(buf2,"%sFTP.Before",SignOn);
if((fp=fopen(buf2,"r"))!=NULL)
{
sendfile(fp,server_socket,ASCII_TYPE,0);
fclose(fp);
}
usprintf(server_socket,banner,Hostname,Version);
FD_ZERO(&readfds);
for(;;)
{
FD_SET(server_socket,&readfds);
if (select(server_socket+1,&readfds,NULL,NULL,NULL)<0) break;
if(!FD_ISSET(server_socket,&readfds)) continue;
cnt=lineRead(LineRead);
if(cnt==0) continue; // EOF
if(cnt==-1)
{
if(LineRead->rl_Line==NULL) goto finish;
continue;
}
buf=LineRead->rl_Line;
rip(buf);
AddLog("%s",buf);
/* Find command in table; if not present, return syntax error */
for(cmdp=commands;*cmdp != NULL;cmdp++)
if(strnicmp(*cmdp,buf,strlen(*cmdp)) == 0)
break;
if(*cmdp == NULL){
usprintf(ftp.control,badcmd);
continue;
}
/* Allow only USER, PASS, QUIT before logging in */
if(ftp.cd == NULL || ftp.path == NULL){
switch(cmdp-commands){
case USER_CMD:
case PASS_CMD:
case QUIT_CMD:
break;
default:
usprintf(ftp.control,notlog);
continue;
}
}
arg = &buf[strlen(*cmdp)];
while(*arg == ' ') arg++;
switch(cmdp-commands)
{
case USER_CMD:
if(timewind(NULL,NULL,NULL)) {
usprintf(ftp.control,notyet,tt1,tt2,
((p = getenv("TZ")) == NULL) ? "GMT" : p);
goto finish;
}
free(ftp.username);
if(!strcmp("anonymous",arg)) ftp.username=strdup("ftp");
else ftp.username=strdup(arg);
if(!stricmp("ftp",ftp.username)) usprintf(ftp.control,givepasa);
else usprintf(ftp.control,givepass);
break;
case TYPE_CMD:
switch(arg[0])
{
case 'A':
case 'a': /* Ascii */
ftp.type = ASCII_TYPE;
usprintf(ftp.control,typeok,arg);
break;
case 'l':
case 'L':
while(*arg != ' ' && *arg != '\0') arg++;
if(*arg == '\0' || *++arg != '8')
{
usprintf(ftp.control,only8);
break;
}
ftp.type = LOGICAL_TYPE;
ftp.logbsize = 8;
usprintf(ftp.control,typeok,arg);
break;
case 'B':
case 'b': /* Binary */
case 'I':
case 'i': /* Image */
ftp.type = IMAGE_TYPE;
usprintf(ftp.control,typeok,arg);
break;
default: /* Invalid */
usprintf(ftp.control,badtype,arg);
break;
}
break;
case QUIT_CMD:
usprintf(ftp.control,bye);
goto finish;
case RETR_CMD:
if(timewind(NULL,NULL,NULL))
{
usprintf(ftp.control,notyet,tt1,tt2,
((p = getenv("TZ")) == NULL) ? "GMT" : p);
goto finish;
}
file=pathname(ftp.cd,arg);
switch(ftp.type) {
case IMAGE_TYPE:
case LOGICAL_TYPE:
mode = "rb";
break;
case ASCII_TYPE:
mode = "r";
break;
}
if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file))
usprintf(ftp.control,noperm);
else if((ftp.fp = fopen(file,mode)) == NULL)
usprintf(ftp.control,cantopen,file,sys_errlist[errno]);
else
{
if(LogLevel>=10) AddLog("RETR %s by %s",file,ftp.username);
if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
usprintf(ftp.control,binwarn,file);
}
sendit(&ftp,"RETR",file);
}
free(file);
break;
case STOR_CMD:
if(timewind(NULL,NULL,NULL)) {
usprintf(ftp.control,notyet,tt1,tt2,
((p = getenv("TZ")) == NULL) ? "GMT" : p);
goto finish;
}
file = pathname(ftp.cd,arg);
switch(ftp.type){
case IMAGE_TYPE:
case LOGICAL_TYPE:
mode = "wb";
break;
case ASCII_TYPE:
mode = "w";
break;
}
if(!permcheck(ftp.path,ftp.perms,STOR_CMD,file))
usprintf(ftp.control,noperm);
else if((ftp.fp = fopen(file,mode)) == NULL)
usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
else
{
if(LogLevel>=5) AddLog("STOR %s by %s",file,ftp.username);
recvit(&ftp,"STOR",file);
}
free(file);
break;
case PORT_CMD:
if(pport(&ftp.port,arg) == -1) usprintf(ftp.control,badport);
else usprintf(ftp.control,portok);
break;
case LIST_CMD:
if(DefDirCommand && ArgDirCommand && !(ftp.perms&FTP_NOEXTDIR))
{
/* User external dir-command, you lose some protection when
using this option */
if(chdir(ftp.cd)) usprintf(ftp.control,nodir,file,sys_errlist[errno]);
else if((ftp.fp=extdir(arg))==NULL) usprintf(ftp.control,nodir,file,sys_errlist[errno]);
else sendit(&ftp,"LIST",DefDirCommand);
}
else
{
file = pathname(ftp.cd,arg);
if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)) usprintf(ftp.control,noperm);
else if((ftp.fp = dir(file,1)) == NULL) usprintf(ftp.control,nodir,file,sys_errlist[errno]);
else sendit(&ftp,"LIST",file);
free(file);
}
break;
case NLST_CMD:
file = pathname(ftp.cd,arg);
if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file))
usprintf(ftp.control,noperm);
else if((ftp.fp = dir(file,0)) == NULL)
usprintf(ftp.control,nodir,file,sys_errlist[errno]);
else sendit(&ftp,"NLST",file);
free(file);
break;
case PASS_CMD:
if(ftp.username == NULL) usprintf(ftp.control,userfirst);
else
{
if(!strcmp(arg,"anonymous")) arg="ftp";
ftplogin(&ftp,arg);
}
break;
case CWD_CMD:
if(!strncmp(arg,"..",2)) arg="/";
file = pathname(ftp.cd,arg);
if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file))
{
usprintf(ftp.control,noperm);
free(file);
}
else if(access(file,0) == 0)
{ /* See if it exists */
/* Succeeded, record in control block */
free(ftp.cd);
ftp.cd = file;
sprintf(buf2,"%s/FTP.Dir",file);
if((fp=fopen(buf2,"r"))!=NULL)
{
sendfile(fp,server_socket,ASCII_TYPE,0);
fclose(fp);
}
usprintf(ftp.control,pwdmsg,file);
}
else
{
/* Failed, don't change anything */
usprintf(ftp.control,nodir,file,sys_errlist[errno]);
free(file);
}
break;
case XPWD_CMD:
case PWD_CMD:
usprintf(ftp.control,pwdmsg,ftp.cd);
break;
case XMKD_CMD:
case MKD_CMD:
file = pathname(ftp.cd,arg);
if(!permcheck(ftp.path,ftp.perms,MKD_CMD,file))
usprintf(ftp.control,noperm);
else if(mkdir(file) == 0)
{
if(LogLevel>=5) AddLog("MKD %s by %s",file,ftp.username);
usprintf(ftp.control,mkdok);
}
else usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
free(file);
break;
case XRMD_CMD:
case RMD_CMD:
file = pathname(ftp.cd,arg);
if(!permcheck(ftp.path,ftp.perms,RMD_CMD,file))
usprintf(ftp.control,noperm);
else if(rmdir(file) == 0)
{
if(LogLevel>=5) AddLog("RMD %s by %s",file,ftp.username);
usprintf(ftp.control,deleok);
}
else usprintf(ftp.control,delefail,sys_errlist[errno]);
free(file);
break;
case ACCT_CMD:
usprintf(ftp.control,unimp);
break;
case STRU_CMD:
if(tolower(arg[0]) != 'f') usprintf(ftp.control,unsupp);
else usprintf(ftp.control,okay);
break;
case MODE_CMD:
if(tolower(arg[0]) != 's') usprintf(ftp.control,unsupp);
else usprintf(ftp.control,okay);
break;
case DELE_CMD:
file = pathname(ftp.cd,arg);
if(!permcheck(ftp.path,ftp.perms,DELE_CMD,file))
usprintf(ftp.control,noperm);
else if(unlink(file) == 0)
{
if(LogLevel>=5) AddLog("DELE %s by %s",file,ftp.username);
usprintf(ftp.control,deleok);
}
else usprintf(ftp.control,delefail,sys_errlist[errno]);
free(file);
break;
// case PASV_CMD:
// passive(&ftp);
// break;
}
}
finish:
free(ftp.username);
free(ftp.path);
free(ftp.cd);
exit(0);
}